/*-------------------------------------------------------------------------
 *
 * snapshot.h
 *	  POSTGRES 快照定义
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/utils/snapshot.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef SNAPSHOT_H
#define SNAPSHOT_H

#include "access/htup.h"
#include "access/xlogdefs.h"
#include "datatype/timestamp.h"
#include "lib/pairingheap.h"
#include "storage/buf.h"


/*
 * 不同的快照类型。我们使用 SnapshotData 结构来表示
 * “常规”（MVCC）快照和具有非 MVCC
 * 语义的“特殊”快照。快照的特定语义由其类型编码。
 *
 * 每种快照类型的行为应与其枚举值一起记录，最好使用
 * 并非特定于单个表 AM 的术语。
 *
 * 使用快照类型而不是像以前那样的回调的原因是
 * 这允许为不同的表 AM 使用相同的快照，而无需每个 AM
 * 有一个回调。
 */
typedef enum SnapshotType
{
	/*-------------------------------------------------------------------------
	 * 元组可见当且仅当该元组对给定的 MVCC 快照有效。
	 *
	 * 在这里，我们考虑以下影响：
	 * - 截至给定快照时间的所有已提交事务
	 * - 此事务的先前命令
	 *
	 * 不包括：
	 * - 快照所示的进行中的事务
	 * - 快照拍摄后开始的事务
	 * - 当前命令所做的更改
	 * -------------------------------------------------------------------------
	 */
	SNAPSHOT_MVCC = 0,

	/*-------------------------------------------------------------------------
	 * 元组可见当且仅当该元组“对自身”有效。
	 *
	 * 在这里，我们考虑以下影响：
	 * - 当前时刻所有已提交的事务
	 * - 此事务的先前命令
	 * - 当前命令所做的更改
	 *
	 * 不包括：
	 * - 进行中的事务（截至当前时刻）
	 * -------------------------------------------------------------------------
	 */
	SNAPSHOT_SELF,

	/*
	 * 任何元组都是可见的。
	 */
	SNAPSHOT_ANY,

	/*
	 * 一个元组在可见的情况下，即该元组作为TOAST行是有效的。
	 */
	SNAPSHOT_TOAST,

	/*-------------------------------------------------------------------------
	 * 一个元组在可见的情况下，意味着该元组是有效的，包括开放
	 * 事务的影响。
	 *
	 * 在这里，我们考虑以下影响：
	 * - 所有已提交和进行中的事务（截至当前时刻）
	 * - 该事务的先前命令
	 * - 当前命令所做的更改
	 *
	 * 在当前事务及已提交/已中止事务的影响方面，这基本上类似于SNAPSHOT_SELF。然而，它
	 * 也包括仍在进行中的其他事务的影响。
	 *
	 * 一个特别的黑客是，当使用这种类型的快照来
	 * 确定元组可见性时，传入的快照结构被用作输出参数，以返回
	 * 影响该元组的并发事务的xids。snapshot->xmin设置为元组的xmin，如果这是
	 * 另一个仍在进行中的事务；或者设置为
	 * InvalidTransactionId，如果元组的xmin已提交良好、已提交死亡或我自己的事务。同样
	 * 对于snapshot->xmax和元组的xmax。如果元组是投机性插入的，这意味着
	 * 插入者可能仍然会在不中止整个事务的情况下撤回插入，相关的令牌也会返回在
	 * snapshot->speculativeToken中。另见InitDirtySnapshot()。
	 * -------------------------------------------------------------------------
	 */
	SNAPSHOT_DIRTY,

	/*
	 * 一个元组在可见的情况下，如果它遵循SNAPSHOT_MVCC的规则，但
	 * 支持在时间旅行上下文中调用（用于在逻辑解码的上下文中解码目录
	 * 内容）。
	 */
	SNAPSHOT_HISTORIC_MVCC,

	/*
	 * 一个元组在可见的情况下，如果该元组可能对某些事务可见；
	 * 如果它对所有人肯定是死的，即可清理的，则返回false。
	 *
	 * 对于可见性检查，snapshot->min必须使用xmin
	 * 地平线进行设置。
	 */
	SNAPSHOT_NON_VACUUMABLE
} SnapshotType;

typedef struct SnapshotData *Snapshot;

#define InvalidSnapshot		((Snapshot) NULL)

/*
 * 表示所有可能快照的结构。
 *
 * 有几种不同类型的快照：
 * * 正常的MVCC快照
 * * 在恢复期间（热备用模式）拍摄的MVCC快照
 * * 在逻辑解码期间使用的历史MVCC快照
 * * 传递给HeapTupleSatisfiesDirty()的快照
 * * 传递给HeapTupleSatisfiesNonVacuumable()的快照
 * * 用于SatisfiesAny、Toast、自我，其中没有成员被访问的快照。
 *
 * TODO：使用NodeTag拆分该结构可能是个好主意,
 * 类似于处理解析器和执行器节点的方式，为每种不同类型的快照
 * 创建一个类型，以避免过载单个字段的含义。
 */
typedef struct SnapshotData
{
	SnapshotType snapshot_type; /* 快照类型 */

	/*
	 * 剩余字段仅用于MVCC快照，在特殊快照中通常
	 * 只是零。（但是xmin和xmax被HeapTupleSatisfiesDirty特殊使用，xmin被
	 * HeapTupleSatisfiesNonVacuumable特殊使用。）
	 *
	 * 一个MVCC快照不能看到XIDs >= xmax的影响。它可以看到
	 * 所有较早XIDs的影响，除了在快照中列出的那些。xmin
	 * 被存储为一种优化，以避免在大多数元组中需要搜索XID数组。
	 */
	TransactionId xmin;			/* 所有XID < xmin对我可见 */
	TransactionId xmax;			/* 所有XID >= xmax对我不可见 */

	/*
	 * 对于正常的MVCC快照，这包含所有正在进行的事务ID，除非
	 * 快照是在恢复期间拍摄的，在这种情况下它是空的。对于历史MVCC快照，其含义是反转的，
	 * 也就是说，它包含xmin和xmax之间的*已提交*事务。
	 *
	 * 注意：所有xip[]中的ID满足xmin <= xip[i] < xmax
	 */
	TransactionId *xip;
	uint32		xcnt;			/* xip[] 中的 xact ids 数量 */

	/*
	 * 对于非历史MVCC快照，这包含正在进行的子事务ID
	 * （如果在恢复期间拍摄，还包括其他正在进行的事务）。对于历史快照，它包含
	 * 分配给已回放事务的*所有*xids，包括顶层xid。
	 *
	 * 注意：subxip[]中的所有ID都>= xmin，但是我们不费心过滤出任何
	 * >= xmax的ID。
	 */
	TransactionId *subxip;
	int32		subxcnt;		/* subxip[]中事务ID的数量 */
	bool		suboverflowed;	/* subxip数组是否溢出？ */

	bool		takenDuringRecovery;	/* 恢复形状快照？ */
	bool		copied;			/* 如果是静态快照，则为false */

	CommandId	curcid;			/* 在我的事务中，CID < curcid是可见的 */

	/*
	 * HeapTupleSatisfiesDirty的额外返回值，在MVCC
	 * 快照中未使用。
	 */
	uint32		speculativeToken;

	/*
	 * 对于SNAPSHOT_NON_VACUUMABLE（希望未来可以有更多），这用于
	 * 确定行是否可以被清理。
	 */
	struct GlobalVisState *vistest;

	/*
	 * 书籍维护信息，由快照管理器使用
	 */
	uint32		active_count;	/* ActiveSnapshot堆栈上的引用计数 */
	uint32		regd_count;		/* RegisteredSnapshots上的引用计数 */
	pairingheap_node ph_node;	/* RegisteredSnapshots堆中的链接 */

	TimestampTz whenTaken;		/* 拍摄快照时的时间戳 */
	XLogRecPtr	lsn;			/* 拍摄时在WAL流中的位置 */

	
/*
	 * GetSnapshotData() 构建此快照时的事务完成计数。
	 * 允许在自上次 GetSnapshotData() 以来没有完成事务时避免重新计算静态快照。
	 */
	uint64		snapXactCompletionCount;
} SnapshotData;

#endif							/* SNAPSHOT_H */
